package com.didispace.chapter310;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author: gx.wu
 * @create: 2023-03-19 21:19
 * @Description:
 */
@Slf4j
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserDao userDao;

    public void insert00Normal(User user){
        log.info("----：{}", user);
        User r = userRepository.save(user);
        log.info("----：{}", r);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void insert01(User user){
        log.info("----：{}", user);
        User r = userRepository.save(user);
        log.info("----：{}", r);
    }

    /**
     * runtimeException，回滚
     * @param user
     * @throws Exception
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert02RuntimeException(User user){
        log.info("----：{}", user);
        User r = userRepository.save(user);
        log.info("----：{}", r);
        throw new RuntimeException("抛出异常!");
    }

    /**
     * 抛出非 runtimeException，不会回滚
     * @param user
     * @throws Exception
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert03Exception(User user) throws Exception {
        userRepository.save(user);
        throw new Exception("抛出异常!");
    }


    /**
     * 捕获抛出的异常，不会回滚
     * @param user
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert04CatchRuntimeException(User user){
        log.info("----：{}", user);
        User r = userRepository.save(user);
        log.info("----：{}", r);
        try {
            throw new RuntimeException("抛出异常!");
        }catch (RuntimeException e) {
            e.printStackTrace();
        }
    }

    /**
     * 同一个里面的普通方法，调用事务方法，事务方法异常无法回滚
     * @param user
     */
    public void insert05SameClassInnerInvoke(User user){
        log.info("----：{}", user);
        User r = userRepository.save(user);
        log.info("----：{}", r);
        insert02RuntimeException(new User(user.getName(), user.getAge()+1, "inner transaction rollback fail"));
    }

    /**
     * 事务调用类中的普通方法，异常一起回滚
     * @param user
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert06SameClassNestNormal(User user){
        log.info("----：{}", user);
        User r = userRepository.save(user);
        log.info("----：{}", r);
        insert00Normal(new User(user.getName(), user.getAge()+1, "nest invoke normal function rollback success"));
        throw new RuntimeException("抛出异常!");
    }


    /**
     * 事务方法内部，调用同一类的其他事务方法，其他事务方法不生效，以普通方法形式调用
     * @param user
     */
    @Transactional(propagation =  Propagation.REQUIRED)
    public void insertO7SameClassNestTransaction(User user) {
        insert01(user);
        insert02RuntimeException(new User(user.getName(), user.getAge()+1, user.getRemark()));
    }

    /**
     * 事务方法内部，调用同一类的其他事务方法，其他事务方法不生效，以普通方法形式调用
     * insert02RuntimeException()方法不会启动事务，所以不存在回滚
     * @param user
     */
    @Transactional(propagation =  Propagation.REQUIRED)
    public void insertO8SameClassNestTransactionCatch(User user) {
        insert01(user);
        try {
            insert02RuntimeException(new User(user.getName(), user.getAge()+1, user.getRemark()));
        }catch (RuntimeException e) {
            log.error("异常：", e.getMessage());
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void insert09RequiresNewNormal(User user){
        log.info("----：{}", user);
        User r = userRepository.save(user);
        log.info("----：{}", r);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void insert10NotSupportedNormal(User user){
        log.info("----：{}", user);
        User r = userRepository.save(user);
        log.info("----：{}", r);
    }

    @Transactional(propagation = Propagation.NEVER)
    public void insert11NeverNormal(User user){
        log.info("----：{}", user);
        int r = userDao.save(user); //Jpa不支持nested，改为JDBCTemplate
        log.info("----：{}", r);
    }


    @Transactional(propagation = Propagation.NESTED)
    public void insert12NestedNormal(User user){
        log.info("----：{}", user);
        int r = userDao.save(user); //Jpa不支持nested，改为JDBCTemplate
        log.info("----：{}", r);
    }


}
